package com.shy.config;

import com.shy.config.handler.AccessDeniedHandlers;
import com.shy.config.handler.FailureHandler;
import com.shy.config.handler.LogoutSuccessHandlers;
import com.shy.config.handler.SuccessHandler;
import com.shy.config.util.TokenFilter;
import jakarta.annotation.Resource;
import org.springframework.context.annotation.Bean;
import org.springframework.security.config.annotation.method.configuration.EnableMethodSecurity;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configurers.AbstractHttpConfigurer;
import org.springframework.security.config.http.SessionCreationPolicy;
import org.springframework.security.web.SecurityFilterChain;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
import org.springframework.stereotype.Component;
import org.springframework.web.cors.CorsConfiguration;
import org.springframework.web.cors.CorsConfigurationSource;
import org.springframework.web.cors.UrlBasedCorsConfigurationSource;

import java.util.List;

@Component
@EnableMethodSecurity(prePostEnabled = true)
public class DlykSecurityConfig {
    @Resource
    private SuccessHandler successHandler;
    @Resource
    private FailureHandler failureHandler;
    @Resource
    private LogoutSuccessHandlers logoutSuccessHandlers;
    @Resource
    private AccessDeniedHandlers accessDeniedHandlers;
    @Resource
    private TokenFilter tokenFilter;

    /**
     * security配置类
     * @param httpSecurity
     * @return
     * @throws Exception
     */
    @Bean
    public SecurityFilterChain securityFilterChain(HttpSecurity httpSecurity) throws Exception {
        return httpSecurity
                /*登录配置*/
                .formLogin((formLogin) -> {
                    formLogin
                            .loginProcessingUrl("/api/login")//登录地址
                            .usernameParameter("loginAct")//账号参数名
                            .passwordParameter("loginPwd")//密码参数名
                            .successHandler(successHandler)//登录成功处理器
                            .failureHandler(failureHandler);//登录失败处理器

                })
                /*登出配置*/
                .logout((logout) -> {
                    logout
                            .logoutUrl("/api/logout")//登出地址
                            .logoutSuccessHandler(logoutSuccessHandlers);//登出成功处理器
                })
                /*添加token过滤器*/
                .addFilterAfter(tokenFilter, UsernamePasswordAuthenticationFilter.class)
                /*异常处理配置*/
                .exceptionHandling((exceptionHandling) -> {
                    exceptionHandling
                            .accessDeniedHandler(accessDeniedHandlers);//权限不足处理器
                })
                /*授权请求配置*/
                .authorizeHttpRequests((authorize) -> {
                    authorize
                            .anyRequest().authenticated();//所有请求都需要认证
                })
                /*session配置*/
                .sessionManagement((sessionManagement) -> {
                    sessionManagement.sessionCreationPolicy(SessionCreationPolicy.STATELESS);//不创建session
                })
                /*跨站伪造*/
                .csrf(AbstractHttpConfigurer::disable)//禁用csrf
                /*解决跨域配置*/
                .cors((cors)->{
                    cors.configurationSource(corsConfigurationSource());
                })
                .build();
    }

    /**
     * 跨域配置
     * @return 匹配所有请求
     */
    public CorsConfigurationSource corsConfigurationSource() {
        CorsConfiguration configuration = new CorsConfiguration();// 跨域配置
        configuration.setAllowedOrigins(List.of("*")); // 允许所有来源
        configuration.setAllowedMethods(List.of("*")); // 允许的方法
        configuration.setAllowedHeaders(List.of("*")); // 允许的头信息
//        configuration.setAllowCredentials(true); // 是否允许发送Cookie
        UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();// 基于路径的跨域配置
        source.registerCorsConfiguration("/**", configuration);// 匹配所有请求
        return source;

    }
}
